package raspberry_pi_app;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;

import bradz.media_server.raspberry_pi_app.R;

import com.facebook.HttpMethod;
import com.facebook.Request;
import com.facebook.Response;
import com.facebook.Session;
import com.facebook.SessionLoginBehavior;
import com.facebook.SessionState;
import com.facebook.Session.Builder;
import com.facebook.Session.OpenRequest;
import com.facebook.model.GraphUser;
import com.facebook.widget.LoginButton;
import com.google.android.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.UserRecoverableAuthException;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.Scopes;
import com.google.android.gms.common.SignInButton;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.plus.Plus;
import com.google.android.gms.plus.model.people.Person.PlacesLived;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class ActivityLogin extends Activity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{

	//Imports
	private GoogleApiClient mGoogleApiClient;
	
	//Variables
	private boolean debug_login,face_book_clicked,mIntentInProgress;
	private static final int RC_SIGN_IN = 0;
	private static final int REQUEST_CODE_RESOLVE_ERR = 42;
	
	//Classes
	private Context self;
	private ClassUberLogger logger;
	private ClassFonts fonts;
	private ClassNetworkHelper helper;
	
	//Elements
    private LoginButton authButton;
    private SignInButton googleButton;
    private Button main_menu,logout;
    private ProgressBar login_progress;
    private ApplicationGlobalVars globals;
	
	Handler myHandler = new Handler() {

  	    @Override
  	    public void handleMessage(Message msg) {
  	        switch (msg.what) {
  	        case 0:
  	            break;
  	        default:
  	            break;
  	        }
  	    }
  	};
	
	public void onCreate(Bundle savedInstanceState) {
	    super.onCreate(savedInstanceState);
	    setContentView(R.layout.activity_login);
	    
	    //debug_login = "goldfish".equals(Build.HARDWARE);
	    
	    debug_login = false;
	    
	    self = this;
	    
	    fonts = new ClassFonts(this.getAssets());
	    logger = new ClassUberLogger("Activity_Login");
	    globals = ((ApplicationGlobalVars) this.getApplication());
	    helper = new ClassNetworkHelper(this,globals);
	    face_book_clicked = false;
	    
	    format_ui();
	    init_social_media_elements();
	    update_buttons();
	}
	
	public void init_social_media_elements(){
		mGoogleApiClient = new GoogleApiClient.Builder(this)
        .addConnectionCallbacks(this)
        .addOnConnectionFailedListener(this)
        .addApi(Plus.API)
        .addScope(Plus.SCOPE_PLUS_LOGIN)
        .build();
	}
	
	public void format_ui(){
		TextView title = (TextView) this.findViewById(R.id.title_text);
		title.setTypeface(fonts.get_font("italic"));
	}
	
	
	private void update_buttons(){
		  
		  login_progress = (ProgressBar) findViewById(R.id.login_progress);
		  
		  authButton = (LoginButton) findViewById(R.id.sign_in_button_facebook);
		  
		  authButton.setOnClickListener(new View.OnClickListener() {
	          public void onClick(View v) {
	        	  
	        	  logger.info("Facebook clicked");
	        	  
	        	  face_book_clicked = true;
	        	  
	        	  login_progress.setVisibility(View.VISIBLE);
	        	  
	        	  Session currentSession = Session.getActiveSession();
	        	    if (currentSession == null || currentSession.getState().isClosed()) {
	        	    	logger.info("Making new Facebook session object...");
	        	        Session session = new Session.Builder(self).build();
	        	        Session.setActiveSession(session);
	        	        currentSession = session;
	        	    }

	        	    if (currentSession.isOpened()) {
	        	    	logger.info("Opening current Facebook session...");
	        	    	//currentSession.closeAndClearTokenInformation();
	        	    	open_active_session();
	        	        // Do whatever u want. User has logged in

	        	    } else if (!currentSession.isOpened()) {
	        	        // Ask for username and password
	            	    logger.info("Opening new Facebook session...");
	        	        OpenRequest op = new Session.OpenRequest((Activity) self);

	        	        op.setLoginBehavior(SessionLoginBehavior.SUPPRESS_SSO);
	        	        op.setCallback(null);

	        	        List<String> permissions = new ArrayList<String>();
	        	        //permissions.add("basic_info");
	        	        permissions.add("public_profile");
	        	        permissions.add("user_friends");
	        	        //permissions.add("user_status");
	        	        permissions.add("email");
	        	        //permissions.add("user_birthday");
	        	        
	        	        op.setPermissions(permissions);

	        	        Session session = new Builder(ActivityLogin.this).build();
	        	        Session.setActiveSession(session);
	        	        session.openForRead(op);
	        	    }
	          }
	      });
		  
		  googleButton = (SignInButton) findViewById(R.id.sign_in_button_google);
		  
		  googleButton.setOnClickListener(new View.OnClickListener() {
	          public void onClick(View v) {
	        	logger.info("Google+ clicked");
	        	face_book_clicked = false;
	        	login_progress.setVisibility(View.VISIBLE);
	          	if (!mGoogleApiClient.isConnecting()) {
	          		logger.info("Connecting to Google+");
	      		    mGoogleApiClient.connect();
	          	}else{
	          		logger.error("Unexpected error occured with Google+ API");
	          		Toast.makeText(self, "An unexpected error has occurred with the Google+ API", 1000).show();
	          		login_progress.setVisibility(View.GONE);
	          	}
	          }
		    });
		  
		  main_menu = (Button) findViewById(R.id.main_menu_button);
		  logout = (Button) findViewById(R.id.log_out_button);
		  
		  logout.setOnClickListener(new View.OnClickListener() {
	          public void onClick(View v) {
	        	  	logger.info("Logout clicked");
	        	  	login_progress.setVisibility(View.VISIBLE);
	        		helper.log_out_network(myHandler);
	          }
		    });
		  
		  main_menu.setOnClickListener(new View.OnClickListener() {
	          public void onClick(View v) {
	        	  Intent myIntent = new Intent(self, ActivityMain.class);
	        	  self.startActivity(myIntent);
	          }
		    });
	  }
	
	private void open_active_session(){
		Session.openActiveSession(this, true, new Session.StatusCallback() {

            @Override
            public void call(final Session session, SessionState state,
                    Exception exception) {

            	if(session != null){
            		logger.info("Facebook Session: " + session.toString());
            		logger.info("Facebook Session Closed: " + String.valueOf(session.isClosed()));
  		      }else{
  		    	  logger.info("No Facebook Session");
  		      }
  		      if(state != null){
  		    	logger.info("State: " + state.toString());
  		      }else{
  		    	logger.info("No State");
  		      }
  		      if(exception != null){
  		    	logger.error("Facebook Exception: " + exception.getMessage());
  		      }else{
  		    	logger.info("No Facebook Exceptions");
  		      }
            	
                if (session.isOpened()) {
                	
                	logger.info("Facebook Session Opened...");

                    Request.executeMeRequestAsync(session,
                            new Request.GraphUserCallback() {

                                @Override
                                public void onCompleted(GraphUser user,Response response) {	
                                	logger.info("Facebook Logged in");
                                    if (user != null) {
                                    	
                                    	logger.info("Returned Data...");
	                                	for(Map.Entry<String, Object> map : user.asMap().entrySet()){
	                                		logger.info("Key: " + map.getKey());
	                                		logger.info(" Value: " + String.valueOf(map.getValue()));
	                                	}
	                                	
	                                	//This had to be taken out due to facebook's sadistic Machiavellian approach to their api
	                                	//JSONObject home_location = (JSONObject) user.asMap().get("location");
	                                	
	                                	String home_string = "TBA";
	                                	
										/*try {
											home_string = home_location.get("name").toString();
										} catch (JSONException e) {
											// TODO Auto-generated catch block
											home_string = "Error";
											logger.error("JSON Error: " + e);
											e.printStackTrace();
										}*/
	                                	
										Map<String, String> map = new HashMap<String, String>();
										map.put("account_name", (String) response.getGraphObject().getProperty("email"));
										map.put("user_name", (String) user.asMap().get("name"));
										map.put("service", "Facebook");
										map.put("location", home_string);
										map.put("gender", (String) user.asMap().get("gender"));
										map.put("birthdate", (String) user.asMap().get("updated_time"));
										map.put("token", Session.getActiveSession().getAccessToken());
										
										get_picture_facebook(map);

                                    }else{
                                    	Toast.makeText(self, "Can't establish a reliable connection to the server.", Toast.LENGTH_LONG).show();
                                    }
                                }
                            });
                }
            }
        });
	}
	
	private void get_picture_facebook(final Map<String, String> map){
		Bundle params = new Bundle();
		params.putBoolean("redirect", false);
		//Define the profile picture dimensions if you want
		//params.putString("height", "200");
		//params.putString("width", "200");
		params.putString("type", "normal");
		/* make the API call */
		new Request(
			Session.getActiveSession(),
		    "/me/picture",
		    params,
		    HttpMethod.GET,
		    new Request.Callback() {
		        public void onCompleted(Response response) {
		            /* handle the result */
		        	logger.info("Printing Response");
		        	if(response.getError() == null){
						try {
							JSONObject json = response.getGraphObject().getInnerJSONObject().getJSONObject("data");
							logger.info("Found picture. Returning: " + json.getString("url"));
							map.put("picture", json.getString("url"));
						} catch (JSONException e1) {
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
		        	}else{
		        		logger.warning("Error encountered loading facebook picture");
		        		map.put("picture", "");
		        	}
		        	get_server_id(map);
		        }
		    }
		).executeAsync();
	}
	
	//This function is where the bottle-neck between the logins happens
	public void get_server_id(Map<String, String> map){
		
		login_progress.setVisibility(View.GONE);
		
		logger.info("Logged into server. Acquiring credentials...");
		logger.info("account_name: " + map.get("account_name"));
		logger.info("user_name: " + map.get("user_name"));
		logger.info("service: " + map.get("service"));
		logger.info("location: " + map.get("location"));
		logger.info("gender: " + map.get("gender"));
		logger.info("birthday: " + map.get("birthdate"));
		logger.info("picture: " + map.get("picture"));
		logger.info("token: " + map.get("token"));
		logger.info("Logged into server. End of credentials...");
		
		Toast.makeText(this, "User is connected!", Toast.LENGTH_LONG).show();	
		
		List<NameValuePair> pairs = new ArrayList<NameValuePair>();
		pairs.add(new BasicNameValuePair("email", map.get("account_name")));
		pairs.add(new BasicNameValuePair("username", map.get("user_name")));
		pairs.add(new BasicNameValuePair("service", map.get("service")));
		pairs.add(new BasicNameValuePair("location", map.get("location")));
		pairs.add(new BasicNameValuePair("gender", map.get("gender")));
		pairs.add(new BasicNameValuePair("birthday", map.get("birthdate")));
		pairs.add(new BasicNameValuePair("token", map.get("token")));
		pairs.add(new BasicNameValuePair("picture", map.get("picture")));
		pairs.add(new BasicNameValuePair("password", ""));

		//logger.info(String.valueOf(debug_login));
		//logger.info(pairs.toString());
		//logger.info(ActivityMain.class.toString());
		
		helper.log_into_network(ActivityMain.class, pairs, debug_login);
	}

	private class SessionStatusCallback implements Session.StatusCallback {
	    @Override
	    public void call(Session session, SessionState state, Exception exception) {
	    	update_buttons();
	    }
	}
	
	public class GetTokenAsync extends AsyncTask<String, String, String>
	{
	
		String token;
		String account_name; 
		String user_name; 
		String service;
		String location; 
		String gender;
		String birthdate; 
		String account_pic;
		GoogleApiClient api_client;
		
		GetTokenAsync(String account_pic, String account_name, String user_name, String service, String location, String gender, String birthdate, GoogleApiClient api_client){
			this.account_pic = account_pic;
			this.account_name = account_name;
			this.user_name = user_name;
			this.service = service;
			this.location = location;
			this.gender = gender;
			this.birthdate = birthdate;
			token = null;
			this.api_client = api_client;
			logger.info("Google+ Token Parsing Initialized");
		}
		
	    @Override
	    protected void onPreExecute()
	        {
	            super.onPreExecute();
	
	        }
	
	    @Override
	    protected String doInBackground(String... params)
	        {
	            String scope = "oauth2:" + Scopes.PLUS_LOGIN;
	            try
	                {
	                    token = GoogleAuthUtil.getToken(self, account_name, scope);
	                }
	            catch (UserRecoverableAuthException e)
	                {
	            		logger.error( "UserRecoverableAuthException");
	                    e.printStackTrace();
	                    token = null;
	                }
	            catch (IOException e)
	                {
	            		logger.error( "IOException");
	                    e.printStackTrace();
	                    token = null;
	                }
	            catch (GoogleAuthException e)
	                {
	            		logger.error( "GoogleAuthException");
	                    e.printStackTrace();
	                    token = null;
	                }
	            catch (Exception e)
	                {
	            		logger.error( "Exception");
	                    e.printStackTrace();
	                    token = null;
	                }
			
	            return null;
	        }
	
	    @Override
	    protected void onPostExecute(String result)
	        {
	            super.onPostExecute(result);
	            
	            //Make sure that we have a server token. Otherwise dont bother
	            if(token != null){
	            	logger.info("Received Google+ Token: " + token);
	            	
	            	Map<String, String> map = new HashMap<String, String>();
	            	
					map.put("account_name", account_name);
					map.put("user_name", user_name);
					map.put("service", service);
					map.put("location", location);
					map.put("gender", gender);
					map.put("birthdate", birthdate);
					map.put("picture", account_pic);
					map.put("token", token);
					
					get_server_id(map);
	            }else{
	            	logger.error("Couldn't verify access token!");
	            	Toast.makeText(self, "Could not verify access token!", 1000).show();
	            }
	        }
	
	}
	
	private void hide_progress(){
		login_progress.setVisibility(View.GONE);
	}
	
	private void logout(){
		  	logger.info("Logging out");
		  	hide_progress();
		  	authButton.setVisibility(View.VISIBLE);
			googleButton.setVisibility(View.VISIBLE);
			logout.setVisibility(View.GONE);
			main_menu.setVisibility(View.GONE);
			globals.invalidate_credentials();
	  }
	
	@Override
	public void onConnectionSuspended(int cause) {
		mGoogleApiClient.connect();
	}
	
	@Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Session session = Session.getActiveSession();
        Session.saveSession(session, outState);
    }
	
	@Override
	protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
    	super.onActivityResult(requestCode, responseCode, intent);
    	
		logger.info("OnActivityResult");
		logger.info("RequestCode: " + requestCode);
		logger.info("ResponseCode: " + responseCode);
		
		login_progress.setVisibility(View.GONE);
		
        //The callback for the google+ login
		if (requestCode == RC_SIGN_IN || requestCode == REQUEST_CODE_RESOLVE_ERR) {
		    if (responseCode != RESULT_OK) {
		    }
		    mIntentInProgress = false;
		    if (!mGoogleApiClient.isConnecting()) {
		      logger.info("Trying to connect to Google+");
		      mGoogleApiClient.connect();
		    }
		}
		
		if(face_book_clicked){
			if (Session.getActiveSession() != null)
		        Session.getActiveSession().onActivityResult(this, requestCode,
		        		responseCode, intent);
	
		    Session currentSession = Session.getActiveSession();
		    if (currentSession == null || currentSession.getState().isClosed()) {
		        Session session = new Session.Builder(self).build();
		        Session.setActiveSession(session);
		        currentSession = session;
		    }
	
		    if (currentSession.isOpened()) {
		    	logger.info("Opening active Facebook session...");
		    	open_active_session();
		    }
		}
		
	}
	
	@Override
	  protected void onStart() {
	    super.onStart();
	    //mGoogleApiClient.connect();
	    logger.info("OnStart called");
	    if(debug_login){
	    	logger.warning("Debug Login = true. Using test data. Login buttons disabled...");
			List<NameValuePair> pairs = new ArrayList<NameValuePair>();
			/*ClassNetworkHelper helper = new ClassNetworkHelper(self,globals);
			pairs.add(new BasicNameValuePair("username", "Brad Zimmerman"));
			pairs.add(new BasicNameValuePair("email", "mauvemoonman@gmail.com"));
			pairs.add(new BasicNameValuePair("service", "Google+"));
			pairs.add(new BasicNameValuePair("location", "Somerville,Massachusetts"));
			pairs.add(new BasicNameValuePair("gender", "male"));
			pairs.add(new BasicNameValuePair("birthday", "08/12/1987"));
			pairs.add(new BasicNameValuePair("token", "test_token"));
			pairs.add(new BasicNameValuePair("password", ""));*/
			
			pairs.add(new BasicNameValuePair("username", "Squanchy Squanch"));
			pairs.add(new BasicNameValuePair("email", "squanchy@yahoo.com"));
			pairs.add(new BasicNameValuePair("service", "Google+"));
			pairs.add(new BasicNameValuePair("location", "Detroit,Michigan"));
			pairs.add(new BasicNameValuePair("gender", "male"));
			pairs.add(new BasicNameValuePair("birthday", "04/12/1980"));
			pairs.add(new BasicNameValuePair("token", "test_token"));
			pairs.add(new BasicNameValuePair("password", ""));
			
			logger.info(String.valueOf(debug_login));
			logger.info(pairs.toString());
			logger.info(ActivityMain.class.toString());
			
			helper.log_into_network(ActivityMain.class, pairs, debug_login);
			
			//List<NameValuePair> pairs = new ArrayList<NameValuePair>();
			
		}
	  }
	
	@Override
	  protected void onResume() {
	    super.onResume();
	    //Turn off the loading circle if we come back to this screen...
	    logger.info("OnResume Called");
	    login_progress.setVisibility(View.GONE);
	    main_menu.setVisibility(View.GONE);
	    if(globals.credentials_loaded()){
	    	authButton.setVisibility(View.GONE);
	    	googleButton.setVisibility(View.GONE);
	    	logout.setVisibility(View.VISIBLE);
	    	main_menu.setVisibility(View.VISIBLE);
	    }else{
	    	authButton.setVisibility(View.VISIBLE);
	    	googleButton.setVisibility(View.VISIBLE);
	    	logout.setVisibility(View.GONE);
	    	main_menu.setVisibility(View.GONE);
	    	
	    }
	    //mGoogleApiClient.connect();
	  }
	  
	  @Override
	  protected void onStop() {
	    super.onStop();
	    logger.info("OnStop Called");
	    if (mGoogleApiClient.isConnected()) {
	      mGoogleApiClient.disconnect();
	    }
	  }
	
	@Override
	public void onConnectionFailed(ConnectionResult result) {
		logger.warning("Google+ Connection Failed!");
		logger.info(result.toString());
		
		
		if (!mIntentInProgress && result.hasResolution()) {
		    try {
		      mIntentInProgress = true;
		      startIntentSenderForResult(result.getResolution().getIntentSender(),REQUEST_CODE_RESOLVE_ERR, null, 0, 0, 0);
		    } catch (SendIntentException e) {
		      // The intent was canceled before it was sent.  Return to the default
		      // state and attempt to connect to get an updated ConnectionResult.
		      mIntentInProgress = false;
		      mGoogleApiClient.connect();
		    }
		  }
	}

	@Override
	public void onConnected(Bundle arg0) {
		String location = "";
		logger.info("Logged in. Printing info...");
		logger.info("account_name: " + Plus.AccountApi.getAccountName(mGoogleApiClient));
		logger.info("user_name: " + Plus.PeopleApi.getCurrentPerson(mGoogleApiClient).getDisplayName());
		logger.info("service: " + "Google+");
		logger.info("location: " + Plus.PeopleApi.getCurrentPerson(mGoogleApiClient).getCurrentLocation());
		for(PlacesLived place : Plus.PeopleApi.getCurrentPerson(mGoogleApiClient).getPlacesLived()){
			//If the place is primary, record it and break
			if(place.isPrimary()){
				location = place.getValue();
				break;
			}
			//If it isn't and there isn't any location yet, record the most recent location and wait to see if another is primary
			if(location.equals("")){
				location = place.getValue();
			}
		}
		 
		int gender = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient).getGender();
		logger.info("gender int: " + gender);
		String gender_string = gender==0?"male":(gender==1?"female":"other");
		 
		logger.info("gender: " + gender_string);
		logger.info("birthday: " + Plus.PeopleApi.getCurrentPerson(mGoogleApiClient).getBirthday());
		logger.info("picture: " + Plus.PeopleApi.getCurrentPerson(mGoogleApiClient).getImage().getUrl());
		logger.info("Logged in. End of info...");
		 
		GetTokenAsync token_finder = new GetTokenAsync(
				 Plus.PeopleApi.getCurrentPerson(mGoogleApiClient).getImage().getUrl(),
				 Plus.AccountApi.getAccountName(mGoogleApiClient),
				 Plus.PeopleApi.getCurrentPerson(mGoogleApiClient).getDisplayName(),
				 "Google+",
				 location,
				 gender_string,
				 Plus.PeopleApi.getCurrentPerson(mGoogleApiClient).getBirthday(),
				 mGoogleApiClient);
		
		//Make sure that we have a token to give our server...
		//Basically makes us harder to hack
		token_finder.execute();
	}

}
